package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

const LUA_REGISTRYINDEX = (-10000)
const LUA_ENVIRONINDEX = (-10001)
const LUA_GLOBALSINDEX = (-10002)
const LUA_TNIL = 0
const LUA_TBOOLEAN = 1
const LUA_TLIGHTUSERDATA = 2
const LUA_TNUMBER = 3
const LUA_TSTRING = 4
const LUA_TTABLE = 5
const LUA_TFUNCTION = 6
const LUA_TUSERDATA = 7
const LUA_TTHREAD = 8

type Lua struct {
	dll   *syscall.LazyDLL
	state uintptr
}

func IntPtr(n int) uintptr {
	return uintptr(n)
}

//func StrPtr(s string) uintptr {
//	return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))
//}

/****
* 字符串转指针
 */
func StrPtr(s string) uintptr {
	dt := []byte(s)
	return uintptr(unsafe.Pointer(&dt[0]))
}

/***
*byte转指针
 */
func BytePtr(s []byte) uintptr {
	return uintptr(unsafe.Pointer(&s[0]))
}

/***
*指针转byte
 */
func PtrByte(r uintptr) []byte {
	if r != 0 {
		p := (*byte)(unsafe.Pointer(r))
		// define a slice to fill with the p string
		data := make([]byte, 0)
		for *p != 0 {
			data = append(data, *p)        // append 1 byte
			r += unsafe.Sizeof(byte(0))    // move r to next byte
			p = (*byte)(unsafe.Pointer(r)) // get the byte value
		}
		return data
	}
	return nil
}

func GetReturn(r uintptr) []byte {
	if r != 0 {
		p := (*byte)(unsafe.Pointer(r))
		// define a slice to fill with the p string
		data := make([]byte, 0)
		for *p != 0 {
			data = append(data, *p)        // append 1 byte
			r += unsafe.Sizeof(byte(0))    // move r to next byte
			p = (*byte)(unsafe.Pointer(r)) // get the byte value
		}
		return data
	}
	return nil

}
func PrintError(r uintptr, r2 uintptr) {
	if r != 0 && r2 != 0 {
		p := (*byte)(unsafe.Pointer(r))
		// define a slice to fill with the p string
		data := make([]byte, 0)

		// loop until find '\0'
		for *p != 0 {
			data = append(data, *p)        // append 1 byte
			r += unsafe.Sizeof(byte(0))    // move r to next byte
			p = (*byte)(unsafe.Pointer(r)) // get the byte value
		}
		name := string(data) // convert to Golang string
		fmt.Println("错误", name)
	}
}

//创建一个对象
func Init(str string) *Lua {
	lua := &Lua{}
	dll32 := syscall.NewLazyDLL(str)
	lua.dll = dll32
	return lua
}

/**
创建一个虚拟机
**/
func (lua *Lua) Lua_newstate() (r1, r2 uintptr, lastErr error) {
	luaState := lua.dll.NewProc("luaL_newstate")
	state, d, e := luaState.Call()
	lua.state = state
	return state, d, e
}

/**
创建一个虚拟机
**/
func (lua *Lua) Lua_close() (r1, r2 uintptr, lastErr error) {
	function := lua.dll.NewProc("lua_close")
	state, d, e := function.Call(lua.state)
	return state, d, e
}

/**
获取字符串 r1等于0返回成功，r2等于0，模块有返回值
**/
func (lua *Lua) Lua_tolstring(p1 int, p2 int) (r1, r2 uintptr, lastErr error) {
	function := lua.dll.NewProc("lua_tolstring")
	state, d, e := function.Call(lua.state, IntPtr(p1), IntPtr(p2))
	return state, d, e
}

/**
获取字符串 r1等于0返回成功，r2等于0，模块有返回值
**/
func (lua *Lua) Lua_tostring(p1 int) (r1, r2 uintptr, lastErr error) {
	return lua.Lua_tolstring(p1, 0)
}

/**
返回一个数字指针
**/
func (lua *Lua) Lua_tonumber(p1 int) (r1, r2 uintptr, lastErr error) {
	function := lua.dll.NewProc("lua_tolstring")
	state, d, e := function.Call(lua.state, IntPtr(p1))
	return state, d, e
}

/**
返回一个数字指针
**/
func (lua *Lua) Lua_tointeger(p1 int) (r1, r2 uintptr, lastErr error) {
	function := lua.dll.NewProc("lua_tointeger")
	state, d, e := function.Call(lua.state, IntPtr(p1))
	return state, d, e
}

/**
加载库
**/
func (lua *Lua) LuaL_openlibs() (r1, r2 uintptr, lastErr error) {

	openLib := lua.dll.NewProc("luaL_openlibs")
	s, d, e := openLib.Call(lua.state)
	return s, d, e
}

/**
加载文件
**/
func (lua *Lua) LuaL_loadfile(name string) (r1, r2 uintptr, lastErr error) {
	loadFile := lua.dll.NewProc("luaL_loadfile")
	s, d, e := loadFile.Call(lua.state, StrPtr(name))
	return s, d, e
}

func (lua *Lua) LuaL_dofile(name string) (r1, r2 uintptr, lastErr error) {
	s, d, e := lua.LuaL_loadfile(name)
	if s == 0 {
		return lua.Lua_pcall(0, -1, 0)
	}
	return s, d, e
}

/**
设置栈顶
**/
func (lua *Lua) Lua_settop(top int) (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_settop")
	s, d, e := functions.Call(lua.state, IntPtr(top))
	return s, d, e
}

/**
弹出栈顶
**/
func (lua *Lua) lua_pop(top int) (r1, r2 uintptr, lastErr error) {
	return lua.Lua_settop(-top - 1)
}

/**
加载字符串
**/
func (lua *Lua) LuaL_loadstring(data string) (r1, r2 uintptr, lastErr error) {

	functions := lua.dll.NewProc("luaL_loadstring")
	s, d, e := functions.Call(lua.state, StrPtr(data))
	return s, d, e
}

/**
加载字符串
**/
func (lua *Lua) LuaL_dostring(data string) (r1, r2 uintptr, lastErr error) {

	s, d, e := lua.LuaL_loadstring(data)
	if s == 0 {
		return lua.Lua_pcall(0, -1, 0)
	}
	return s, d, e
}

/**
加载字符串
**/
func (lua *Lua) Lua_pcall(p1 int, p2 int, p3 int) (r1, r2 uintptr, lastErr error) {

	functions := lua.dll.NewProc("lua_pcall")
	s, d, e := functions.Call(lua.state, IntPtr(p1), IntPtr(p2), IntPtr(p3))
	return s, d, e
}

/**
压栈一个字符串
**/
func (lua *Lua) Lua_pushstring(str string) (r1, r2 uintptr, lastErr error) {

	functions := lua.dll.NewProc("lua_pushstring")
	s, d, e := functions.Call(lua.state, StrPtr(str))
	return s, d, e
}

/**
压栈一个数字
**/
func (lua *Lua) Lua_pushnumber(num int) (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_pushnumber")
	s, d, e := functions.Call(lua.state, IntPtr(num))
	return s, d, e
}

/**
压栈一个空
**/
func (lua *Lua) Lua_pushnil() (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_pushnil")
	s, d, e := functions.Call(lua.state)
	return s, d, e
}

/**
压栈一个数字
**/
func (lua *Lua) lua_pushinteger(num int) (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_pushinteger")
	s, d, e := functions.Call(lua.state, IntPtr(num))
	return s, d, e
}

/**
设置全局变量
*/
func (lua *Lua) Lua_setglobal(name string) (r1, r2 uintptr, lastErr error) {
	return lua.Lua_setfield(LUA_GLOBALSINDEX, name)
}

/**
压栈一个字符串
num -10002代表全局变量
**/

func (lua *Lua) Lua_setfield(num int, name string) (r1, r2 uintptr, lastErr error) {

	functions := lua.dll.NewProc("lua_setfield")
	s, d, e := functions.Call(lua.state, IntPtr(num), StrPtr(name))
	return s, d, e
}

/***
获取全局变量
*/
func (lua *Lua) Lua_getglobal(name string) (r1, r2 uintptr, lastErr error) {
	return lua.Lua_getfield(LUA_GLOBALSINDEX, name)
}

/**
压栈一个字符串
num -10002代表全局变量
**/
func (lua *Lua) Lua_getfield(num int, name string) (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_getfield")
	s, d, e := functions.Call(lua.state, IntPtr(num), StrPtr(name))
	return s, d, e
}

/***
创建表
*/
func (lua *Lua) Lua_newtable() (r1, r2 uintptr, lastErr error) {
	return lua.Lua_createtable(0, 0)
}

/**
创建表格
**/
func (lua *Lua) Lua_createtable(num int, num2 int) (r1, r2 uintptr, lastErr error) {

	functions := lua.dll.NewProc("lua_createtable")
	s, d, e := functions.Call(lua.state, IntPtr(num), IntPtr(num2))
	return s, d, e
}

/**
获取lua类型
**/
func (lua *Lua) Lua_type(num int) (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_type")
	s, d, e := functions.Call(lua.state, IntPtr(num))
	return s, d, e
}

/**
获取lua类型
**/
func (lua *Lua) Lua_istable(num int) int {
	s, _, _ := lua.Lua_type(num)
	if s == LUA_TTABLE {
		return 1
	} else {
		return 0
	}
}

/**
设置表格
**/
func (lua *Lua) Lua_settable(num int) (r1, r2 uintptr, lastErr error) {

	functions := lua.dll.NewProc("lua_settable")
	s, d, e := functions.Call(lua.state, IntPtr(num))
	return s, d, e
}

/**
获取下一个
**/
func (lua *Lua) Lua_next(num int) (r1, r2 uintptr, lastErr error) {
	functions := lua.dll.NewProc("lua_next")
	s, d, e := functions.Call(lua.state, IntPtr(num))
	return s, d, e
}
